#include "stdafx.h"
#include "http_servlet.h"
typedef struct
{
	std::string msg = "";
	std::string stamp = "";
	std::string tpass_msg = "";
	float snippet_time = 0;
} FUNASR_RECOG_RESULT;

http_servlet::http_servlet(acl::socket_stream *conn, int *connect_num_)
	: acl::HttpServlet(conn), connect_num(connect_num_)
{
}

http_servlet::~http_servlet(void)
{
	FunWfstDecoderUnloadHwsRes(decoder_handle_);
	FunASRWfstDecoderUninit(decoder_handle_);
}

bool http_servlet::doError(acl::HttpServletRequest &,
						   acl::HttpServletResponse &res)
{
	res.setStatus(400);
	res.setContentType("text/html; charset=");
	// 发送 http 响应头
	if (res.sendHeader() == false)
		return false;

	// 发送 http 响应体
	acl::string buf;
	buf.format("<root error='some error happened!' />\r\n");
	(void)res.getOutputStream().write(buf);
	return false;
}

bool http_servlet::doOther(acl::HttpServletRequest &,
						   acl::HttpServletResponse &res, const char *method)
{
	res.setStatus(400);
	res.setContentType("text/html; charset=");
	// 发送 http 响应头
	if (res.sendHeader() == false)
		return false;
	// 发送 http 响应体
	acl::string buf;
	buf.format("<root error='unkown request method %s' />\r\n", method);
	(void)res.getOutputStream().write(buf);
	return false;
}

bool http_servlet::doGet(acl::HttpServletRequest &req,
						 acl::HttpServletResponse &res)
{
	return doPost(req, res);
}

bool http_servlet::doPost(acl::HttpServletRequest &req,
						  acl::HttpServletResponse &res)
{
	res.setContentType("text/html; charset=utf-8") // 设置响应字符集
		.setKeepAlive(req.isKeepAlive())		   // 设置是否保持长连接
		.setContentEncoding(true)				   // 自动支持压缩传输
		.setChunkedTransferEncoding(true);		   // 采用 chunk 传输方式

	acl::string buf;
	buf.format("ok");

	// 发送 http 响应体，因为设置了 chunk 传输模式，所以需要多调用一次
	// res.write 且两个参数均为 0 以表示 chunk 传输数据结束
	bool ret = res.write(buf) && res.write(NULL, 0);
	return ret;
}

bool http_servlet::doWebSocket(HttpRequest &req, HttpResponse &)
{
	acl::socket_stream &conn = req.getSocketStream();
	acl::websocket in(conn), out(conn);

	while (true)
	{
		if (!in.read_frame_head())
		{
			LOG(ERROR) << "read_frame_head error";
			return false;
		}

		bool ret;
		unsigned char opcode = in.get_frame_opcode();
		switch (opcode)
		{
		case acl::FRAME_PING:
			ret = doPing(in, out);
			break;
		case acl::FRAME_PONG:
			ret = doPong(in, out);
			break;
		case acl::FRAME_CLOSE:
			ret = doClose(in, out);
			break;
		case acl::FRAME_TEXT:
			ret = doMsg(in, out);
			break;
		case acl::FRAME_BINARY:
			ret = doMsg(in, out);
			break;
		case acl::FRAME_CONTINUATION:
			ret = false;
			LOG(INFO) << "1-invalid opcode: " << opcode;
			break;
		default:
			LOG(INFO) << "2-invalid opcode: " << opcode;
			ret = false;
			break;
		}

		if (ret == false)
		{
			break;
		}
	}

	return false;
}

acl::string http_servlet::parseMsg(acl::string Msg)
{
	acl::json info(Msg);
	// python进来的进来{"query": "1"} ，acl格式化后变为{"query":"1"}，肯定不相等了
	bool isFinished = false;
	bool is_speaking = true;
	bool itn = true;
	int sampling_rate = 16000;

	if (info["wav_format"])
	{
		const char *format = info["wav_format"]->get_text();
		wav_format_ = format;
	}

	if (info["audio_fs"])
	{
		sampling_rate = (int)*(info["audio_fs"]->get_int64());
	}

	if (info["is_finished"])
	{
		isFinished = *(info["is_finished"]->get_bool());
	}

	if (info["is_speaking"])
	{
		is_speaking = *(info["is_speaking"]->get_bool());
	}

	if (info["itn"])
	{
		itn = *(info["itn"]->get_bool());
	}

	if (info["query"])
	{
		acl::string out = "";
		out.format("{\"count\":%d}", *connect_num);
		return out;
	}

	if (info["hotwords"])
	{
		std::unordered_map<std::string, int> merged_hws_map;
		acl::json_node *parent = info["hotwords"]->get_obj();
        if(parent){
            acl::json_node *iter = parent->first_child();
            while (iter)
            {
                const char *tag = iter->tag_name();
                const char *weight = iter->get_text();
                merged_hws_map.insert({tag, atoi(weight)});
                iter = parent->next_child();
            }

            if (hws_map_)
            {
                merged_hws_map.insert(hws_map_->begin(), hws_map_->end());
            }

            std::string nn_hotwords = "";
            for (const auto &pair : merged_hws_map)
            {
                nn_hotwords += " " + pair.first;
                LOG(INFO) << pair.first << " : " << pair.second;
            }

            if (merged_hws_map.size() > 0)
            {
                FunWfstDecoderLoadHwsRes(decoder_handle_, var_cfg_fst_inc_wts, merged_hws_map);
                embedding_ = CompileHotwordEmbedding(asr_handle_, nn_hotwords);
            }
        }
	}

	if (isFinished || !is_speaking)
	{
		acl::string asr_result;
		acl::string stamp_res;
		acl::string stamp_sents = "";

		acl::string out = "{\"text\":[], \"timestamp\":[]}";
		try
		{
			FUNASR_RESULT Result = FunOfflineInferBuffer(
				asr_handle_, waveBuffer_.c_str(), waveBuffer_.size(), RASR_NONE, NULL, embedding_, sampling_rate, wav_format_, itn, decoder_handle_);

			waveBuffer_.clear();

			if (!Result)
			{
				return out;
			}

			asr_result = FunASRGetResult(Result, 0); // get decode result
			stamp_res = FunASRGetStamp(Result);
			stamp_sents = FunASRGetStampSents(Result);
			FunASRFreeResult(Result);
			out.format("{\"stamp_sents\":%s,\"text\":\"%s\", \"timestamp\":%s}", stamp_sents.c_str(), asr_result.c_str(), stamp_res.c_str());
		}
		catch (std::exception const &e)
		{
			// LOG(ERROR) << e.what();
			out.format("{\"stamp_sents\":[],\"text\":\"\", \"timestamp\":[], \"error\":%s}", e.what());
		}
		return out;
	}

	return "";
}

bool http_servlet::doMsg(acl::websocket &in, acl::websocket &out)
{
	acl::string tbuf((size_t)in.get_frame_payload_len() + 1);

	char buf[4096];
	while (true)
	{
		int ret = in.read_frame_data(buf, sizeof(buf) - 1);
		if (ret == 0)
		{
			break;
		}

		if (ret < 0)
		{
			LOG(ERROR) << "read_frame_data error";
			return false;
		}

		tbuf.append(buf, ret);
	}

	unsigned char opcode = in.get_frame_opcode();
	if (opcode == acl::FRAME_BINARY)
	{
		waveBuffer_ += tbuf;
		return true;
	}
	else
	{
		tbuf += "\0";
		acl::string result = parseMsg(tbuf);
		if (!result.empty())
		{
			out.set_frame_fin(true)
				.set_frame_opcode(acl::FRAME_TEXT)
				.set_frame_payload_len(result.size());
			return out.send_frame_data(result.c_str(), result.size());
		}
		return true;
	}
	return false;
}

bool http_servlet::doPing(acl::websocket &in, acl::websocket &out)
{
	unsigned long long len = in.get_frame_payload_len();
	if (len == 0)
	{
		if (out.send_frame_pong((const void *)NULL, 0) == false)
			return false;
		else
			return true;
	}

	out.reset().set_frame_fin(true).set_frame_opcode(acl::FRAME_PONG).set_frame_payload_len(len);

	char buf[4096];
	while (true)
	{
		int ret = in.read_frame_data(buf, sizeof(buf) - 1);
		if (ret == 0)
			break;
		if (ret < 0)
		{
			LOG(ERROR) << "read_frame_data error";
			return false;
		}

		buf[ret] = 0;
		// printf("read: [%s]\r\n", buf);
		if (out.send_frame_data(buf, ret) == false)
		{
			LOG(ERROR) << "send_frame_data error";
			return false;
		}
	}

	return true;
}

bool http_servlet::doPong(acl::websocket &in, acl::websocket &)
{
	unsigned long long len = in.get_frame_payload_len();
	if (len == 0)
		return true;

	char buf[4096];
	while (true)
	{
		int ret = in.read_frame_data(buf, sizeof(buf) - 1);
		if (ret == 0)
			break;
		if (ret < 0)
		{
			LOG(ERROR) << "read_frame_data error";
			return false;
		}

		buf[ret] = 0;
		// printf("read: [%s]\r\n", buf);
	}

	return true;
}

bool http_servlet::doClose(acl::websocket &, acl::websocket &)
{
	// acl::socket_stream &conn = in.get_stream();
	// logger("peer close from %s, fd %d", conn.get_peer(), conn.sock_handle());
	return false;
}

void http_servlet::setAsrHandle(FUNASR_HANDLE handle)
{
	asr_handle_ = handle;
	decoder_handle_ =
		FunASRWfstDecoderInit(asr_handle_, ASR_OFFLINE, var_cfg_global_beam, var_cfg_lattice_beam, var_cfg_am_scale);
}

void http_servlet::setHotwords(std::shared_ptr<std::unordered_map<std::string, int>> hotwords)
{
	hws_map_ = hotwords;
	LOG(INFO) << "hotwords: ";

	std::string nn_hotwords = "";
	for (const auto &pair : *hws_map_)
	{
		nn_hotwords += " " + pair.first;
		LOG(INFO) << pair.first << " : " << pair.second;
	}
	FunWfstDecoderLoadHwsRes(decoder_handle_, var_cfg_fst_inc_wts, *hws_map_);
	embedding_ = CompileHotwordEmbedding(asr_handle_, nn_hotwords);
}
